Титановый отвар
Python: ещё одна малоизвестная штучка
4/02/2021

Существует чудесный PEP3102, который, в общем-то, никаких новых механик в язык не привносит, но позволяет добавить порядку в код. Его название — keyword-only arguments — может слегка сбить с толку, но сейчас всё станет понятно.

Взгляните на сигнатуру этой функции. Неважно, что именно она делает, главное, что у неё есть порядковые аргументы и именованные:

def upload_to_s3(bucket, file, encrypt=True):

Вроде всё хорошо. Но есть один момент. Оба этих варианта вызова функции равнозначны и дозволены:

upload_to_s3(bucket, file, True)
upload_to_s3(bucket, file, encrypt=True)

Хорошо ли это? Пока вы помните, какой именно именованный аргумент скрывается за безличным True — да. В маленьких скриптах, в небольших программках это совершенно легитимно. Если вам не лень смотреть каждый раз на сигнатуру функции, пользуясь подсказкой IDE, или переходить к её определению — тоже всё ок. Но ведь лень же, да? Лень.

Через некоторое время функция может получить ещё один именованный параметр. Например, так:

def upload_to_s3(bucket, file, duplicate_to_glacier=False, encrypt=True):

И всё. Проблема даже не в том, что нужно ходить к сигнатуре, чтобы вспомнить, какой аргумент за что отвечает. Проблема гораздо серьёзней: если вы или кто-то другой добавляет ещё один именованный аргумент до тех, что уже существуют, логика сломается. Везде, где функция вызывается без именованных аргументов. Теперь вызов upload_to_s3(bucket, file, True) будет означать не «зашифровать файл в S3», а «дублировать файл в Glacier».

Чтобы полностью убрать возможность таких ошибок, нужно добавить звёздочку перед именованными аргументами в сигнатуре:

def upload_to_s3(bucket, file, *, encrypt=True):

Теперь попытка вызвать функцию неправильно бросит исключение TypeError:

TypeError: upload_to_s3() takes 2 positional arguments but 3 were given

Перечислю убитых зайцев:

  • не нужно держать в памяти смысл аргументов, вы их обязаны указывать явно;
  • не нужно держать в голове, что аргументы добавлять нужно только в конец сигнатуры («защита от джунов»);
  • код становится более читабельным.